package service

import (
	"crypto/md5"
	"encoding/hex"
	"go-toy/constant"
	redisClient "go-toy/database/redis"
	"go-toy/util"
	"strconv"
	"time"

	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"
)

type Base struct {
	db         *gorm.DB
	primaryKey string
	columns    []string
	conditions map[string]any
	order      any
	offset     int
	limit      int
}

func (b *Base) GeneralList(total *int64, result any) (err error) {
	// 启用日志输出
	query := b.db.Session(&gorm.Session{Logger: b.db.Logger})

	// Apply conditions
	if len(b.conditions) > 0 {
		query = query.Where(b.conditions)
	}

	// Apply order
	if b.order != nil {
		query = query.Order(b.order)
	}

	// Apply columns
	if len(b.columns) > 0 {
		query = query.Select(b.columns)
	}

	countSql := query.ToSQL(func(tx *gorm.DB) *gorm.DB {
		return tx.Count(total)
	})
	hashCountSql := md5.Sum([]byte(countSql))
	md5key := hex.EncodeToString(hashCountSql[:])
	b.CacheTotal(md5key, total) // get total from cache
	if *total == 0 {
		err = query.Count(total).Error
		b.CacheTotal(md5key, total) // set total to cache
		if err != nil {
			return err
		}
	}

	// Apply offset and limit
	query = query.Offset(b.offset).Limit(b.limit)

	// Execute query
	err = query.Find(result).Error
	if err != nil {
		return err
	}

	return err
}

// Get/Set list total from/to cache
func (b *Base) CacheTotal(key string, total *int64) {
	key = constant.HOT_SPOT_TOTAL_PREFIX + key

	if *total > int64(0) {
		// Set cache
		redisClient.Client.Set(redisClient.Ctx, key, *total, 5*time.Second)
	} else {
		// Get cache
		result, err := redisClient.Client.Get(redisClient.Ctx, key).Result()
		if err == redis.Nil {
			*total = 0
		} else if err != nil {
			util.ServicePanic(err)
		}
		if result != "" {
			*total, err = strconv.ParseInt(result, 10, 64)
			if err != nil {
				util.ServicePanic(err)
			}
		} else {
			*total = 0
		}
	}
}
